package com.spring_mysql_redis.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.spring_mysql_redis.dto.UserLikCountDTO;
import com.spring_mysql_redis.dto.UserLikesDto;
import com.spring_mysql_redis.entity.Dynamic;
import com.spring_mysql_redis.entity.UserLikes;
import com.spring_mysql_redis.eum.LikedStatusEum;
import com.spring_mysql_redis.mapper.DynamicMapper;
import com.spring_mysql_redis.mapper.UserLikesMapper;
import com.spring_mysql_redis.service.ISStockService;
import com.spring_mysql_redis.service.UserLikesService;
import com.spring_mysql_redis.utils.RedisKeyUtils;
import com.spring_mysql_redis.utils.TimeUtitl;
import org.apache.shiro.subject.ExecutionException;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class UserLikesServiceImpl implements UserLikesService {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private UserLikesMapper userLikesMapper;

    @Resource
    private DynamicMapper dynamicMapper;

    @Resource
    private ISStockService isStockService;

    @Override
    public Integer selectLike(Integer dynamicId, Integer userId) {
        String strDynamicId= dynamicId + "";
        String strUserId=userId+"";
        //先查数据库
        UserLikes select = userLikesMapper.selectOne(new LambdaQueryWrapper<UserLikes>()
                .eq(UserLikes::getDynamicId, dynamicId)
                .eq(UserLikes::getUserId, userId));
        if(select != null){
            if (redisTemplate.opsForHash().hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(strDynamicId, strUserId))) {
                String o = redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(strDynamicId, strUserId)).toString();
                if ("1".equals(o)) {
                    //正正得负
                    return 20;
                }
                if ("0".equals(o)) {
                    return 10;
                }
            }
            return 10;
        }else {
            if (redisTemplate.opsForHash().hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(strDynamicId, strUserId))) {
                String o = redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(strDynamicId, strUserId)).toString();
                if ("1".equals(o)) {
                    return 10;
                }
                if ("0".equals(o)) {
                    return 20;
                }
            }
            return 20;
        }
    }

    public Integer likes(String dynamicId, String userId) {
        String likedKey = RedisKeyUtils.getLikedKey(dynamicId, userId);
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, dynamicId, 1);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, likedKey, LikedStatusEum.LIKE.getCode());
        return 200;
    }


    public void unLikes(String dynamicId, String userId) {
        String likedKey = RedisKeyUtils.getLikedKey(dynamicId, userId);
        redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, dynamicId, -1);
        redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, likedKey);
    }

    @Override
    public Object likeState(Integer dynamicId, Integer userId) {
        String strDynamicId= dynamicId + "";
        String strUserId=userId+"";
        if (redisTemplate.opsForHash().hasKey(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(strDynamicId, strUserId))) {
            String o = redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED, RedisKeyUtils.getLikedKey(strDynamicId, strUserId)).toString();
            if ("1".equals(o)) {
                unLikes(strDynamicId, strUserId);
                return LikedStatusEum.UNLIKE;
            }
            if ("0".equals(o)) {
                likes(strDynamicId, strUserId);
                return LikedStatusEum.LIKE;
            }
        }
        likes(strDynamicId, strUserId);
        return LikedStatusEum.LIKE;
    }
    /**
     * Date: 2022/9/15
     * 点赞动态对应用户
     */
    public List<UserLikesDto> getLikedDataFromRedis() {
        Cursor<Map.Entry<Object, Object>> scan = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
        List<UserLikesDto> list = new ArrayList<>();
        while (scan.hasNext()) {
            Map.Entry<Object, Object> entry = scan.next();
            String key = (String) entry.getKey();
            String[] split = key.split("::");
            Integer dynamicId = Integer.parseInt(split[0]);
            Integer userId = Integer.parseInt(split[1]);
            Integer value = (Integer) entry.getValue();
            /**
             * Date: 2022/9/31
             * 查询是否存在该动态对应用户的点赞，有则删除，跳过当前循环，因为likeState（）方法在redis没该数据的情况下，用户点第一次调用的是点赞方法
             * 第二次是删除redis中点赞方法，如果mysql存在该数据且状态为点赞，redis存在该数据，相加未取消点赞，更新mysql状态或删除该数据
             * 跳过该循环
             */
            UserLikes userLikes = userLikesMapper.selectOne(new QueryWrapper<UserLikes>().eq("dynamic_id", dynamicId).eq("user_id", userId));
            if(userLikes != null){
                Integer del = userLikesMapper.deleteById(userLikes.getId());
                //删除redis中键值，避免后面程序出错导致脏数据
                redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
                //redis中该动态赞减二（因为调用了likes方法，加一）
                redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, dynamicId+"", -2);
                continue;
            }
            //组装成 UserLike 对象
            UserLikesDto userLikeDetail = new UserLikesDto(dynamicId, userId, TimeUtitl.dateTime(), value);
            //存到 list
            list.add(userLikeDetail);
        }
        return list;
    }

    /**
     * Date: 2022/9/15
     * 列数
     */
    public List<UserLikCountDTO> getLikedCountFromRedis() {
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);
        List<UserLikCountDTO> list = new ArrayList<>();
        while (cursor.hasNext()) {
            Map.Entry<Object, Object> map = cursor.next();
            String key = (String) map.getKey();
            Integer value = (Integer) map.getValue();
            Integer up = this.updateDynamicLikes(Integer.parseInt(key));
            UserLikCountDTO userLikCountDTO = new UserLikCountDTO(Integer.parseInt(key), value);
            list.add(userLikCountDTO);
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key);
        }

        return list;
    }

    /**
     * Date: 2022/9/31
     * 保存点赞动态对应用户方法
     */
    public String saveData() {

        // 省略获取数据
        // 需要去入库的数据
        List list = getLikedDataFromRedis();

        //处理数据，将数据切分成多个，多线程并发执行插入操作。
        int count = 10;
        int listSize = list.size();        //数据集合大小
        int runSize = (listSize/count)+1;  //开启的线程数
        List<Object> newlist = null;       //存放每个线程的执行数据
        //使用的线程数
        try {
            for (int i = 0; i < runSize; i++) {
                if((i+1)==runSize){
                    int startIndex = (i*count);
                    int endIndex = list.size();
                    newlist = list.subList(startIndex,endIndex);
                }else{
                    int startIndex = (i*count);
                    int endIndex = (i+1)*count;
                    newlist= list.subList(startIndex, endIndex);
                }
                //service 中实现的用@Async 注解标注的插入方法
                isStockService.batchSaveList(newlist);
            }
            return "SUCCESS";
        } catch (ExecutionException e) {
            //线程异常返回
            return "";
        }
    }

    /**
     * Date: 2022/9/31
     * 删除点赞动态对应用户方法
     */
    public String delLikedDataFromRedis() {
        Cursor<Map.Entry<Object, Object>> scan = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
        while (scan.hasNext()) {
            Map.Entry<Object, Object> entry = scan.next();
            String key = (String) entry.getKey();
            redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
        }
        return "delete成功";
    }

    /**
     * Date: 2022/9/31
     * 更新动态赞数
     */
    @Override
    public Integer updateDynamicLikes(Integer dynamicId) {
        System.out.println(dynamicId+"update--------------------------------------------------------------------------------------------");
        Dynamic dynamic = dynamicMapper.selectById(dynamicId);
        if(dynamic != null){
            //动态的赞数量
            Integer likes = userLikesMapper.selectCount(new QueryWrapper<UserLikes>().eq("dynamic_id", dynamicId));
            dynamic.setLikes(likes);
            //更新动态赞
            Integer up = dynamicMapper.updateById(dynamic);
        }
        return 200;
    }

    @Override
    public void delLikeList(Integer dynamicId) {
        LambdaQueryWrapper<UserLikes> wrapper = new LambdaQueryWrapper<UserLikes>().eq(UserLikes::getDynamicId, dynamicId);
        if (wrapper != null){
            userLikesMapper.delete(wrapper);
        }
    }

}
